#include "CodecUtil.hpp"

/*
	NALU头解析
	+-+-+-+-+-+-+-+-+
	|0|1|2|3|4|5|6|7|
	+-+-+-+-+-+-+-+-+
	|F|NRI|  Type   |
	+-+-+-+-+-+-+-+-+
	F: 1个比特，forbidden_zero_bit. 在 H.264 规范中规定了这一位必须为 0.
	NRI：2个比特. nal_ref_idc. 取00~11,似乎指示这个NALU的重要性,如00的NALU解码器可以丢弃它而不影响图像的回放.
	Type：  5个比特. nal_unit_type. 这个NALU单元的类型.简述如下:
	0		未定义
	1-23	NAL单元	单个NAL单元包
	24		STAP-A	单一时间的组合包
	25		STAP-B	单一时间的组合包
	26		MTAP16	多个时间的组合包
	27		MTAP24	多个时间的组合包
	28		FU-A	分片的单元
	29		FU-B	分片的单元
	30-31			未定义
*/

const static uint8_t IDR_IN_SINGLE_SLICE = 5;
const static uint8_t SPS_IN_SINGLE_SLICE = 7;
const static uint8_t PPS_IN_SINGLE_SLICE = 8;
const static uint8_t STP_A_24 = 24;
const static uint8_t FU_A_28 = 28;

static uint8_t LAST_FIVE_BIT = 0x1f;

namespace Hi {

static bool SetHasAttributeByNormalNalType(PayloadDescriptor* payloadDescriptor, uint8_t nalType);
static void SetHasAttribute(PayloadDescriptor* payloadDescriptor, uint8_t nalType);
static void SetHasAttribute_24(PayloadDescriptor* payloadDescriptor, uint8_t *data, size_t len);
	
PayloadDescriptor* ParserH264PayLoad(uint8_t *data, size_t len) {
	if (len < 3) {
		return nullptr;
	}
	
	PayloadDescriptor* payloadDescriptor = new PayloadDescriptor(); 

	uint8_t nalType = data[0] & LAST_FIVE_BIT;
	bool ret = SetHasAttributeByNormalNalType(payloadDescriptor, nalType);
	if (ret) {
		return payloadDescriptor;
	}
	
	if (STP_A_24 == nalType) {		
		SetHasAttribute_24(payloadDescriptor, data, len);
		return payloadDescriptor;
	}
	
	
	if (FU_A_28 == nalType) {			
		uint8_t fuHeader = data[1];
		uint8_t nalType = fuHeader & LAST_FIVE_BIT;		
		SetHasAttributeByNormalNalType(payloadDescriptor, nalType);
		return payloadDescriptor;
	}
	
	return payloadDescriptor;
}


static bool SetHasAttributeByNormalNalType(PayloadDescriptor* payloadDescriptor, uint8_t nalType) {
	switch (nalType) {
		case IDR_IN_SINGLE_SLICE: {// IDR
			// MS_DEBUG_TAG(rtp, "IDR IN STAP-A PACKET");
			payloadDescriptor->has_idr = true;
			return true;
		}
		case SPS_IN_SINGLE_SLICE: { // SPS
			//MS_DEBUG_TAG(rtp, "SPS IN STAP-A PACKET");
			payloadDescriptor->has_sps = true;
			return true;
		}
		case PPS_IN_SINGLE_SLICE:{ // PPS
			//MS_DEBUG_TAG(rtp, "PPS IN STAP-A PACKET");
			payloadDescriptor->has_pps = true;
			return true;
		} default: {
			return false;
		}
	}
}


/**
   Figure 7 presents an example of an RTP packet that contains an STAP-
   A.  The STAP contains two single-time aggregation units, labeled as 1
   and 2 in the figure.

	   0                   1                   2                   3
	   0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	  |                          RTP Header                           |
	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	  |STAP-A NAL HDR |         NALU 1 Size           | NALU 1 HDR    |
	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	  |                         NALU 1 Data                           |
	  :                                                               :
	  +               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	  |               | NALU 2 Size                   | NALU 2 HDR    |
	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	  |                         NALU 2 Data                           |
	  :                                                               :
	  |                               +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
	  |                               :...OPTIONAL RTP padding        |
	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

	  Figure 7.  An example of an RTP packet including an STAP-A and two
		 single-time aggregation units
*/
static void SetHasAttribute_24(PayloadDescriptor* payloadDescriptor, uint8_t *data, size_t len) {	

	size_t index = 1;
	while (index + 2 < len)	{
		uint8_t nalType = data[index + 2] & LAST_FIVE_BIT;
		size_t naluSize = data[index] * 256 + data[index + 1];
		
		SetHasAttributeByNormalNalType(payloadDescriptor, nalType);
		
		index += 2;
		index += naluSize;
	}
}
}

